MongoDB 运维管理
本文档介绍 MongoDB 的备份恢复、监控、性能调优和安全配置。
备份与恢复
mongodump / mongorestore
bash
# 备份整个数据库
mongodump --uri="mongodb://localhost:27017/mydb" --out=/backup/$(date +%Y%m%d)
# 备份指定集合
mongodump --uri="mongodb://localhost:27017/mydb" --collection=users --out=/backup/
# 备份并压缩
mongodump --uri="mongodb://localhost:27017/mydb" --gzip --archive=/backup/mydb.gz
# 备份副本集(从从节点备份)
mongodump --uri="mongodb://secondary:27017/mydb?readPreference=secondary" --out=/backup/
# 恢复数据库
mongorestore --uri="mongodb://localhost:27017/mydb" /backup/20240115/mydb/
# 恢复压缩备份
mongorestore --uri="mongodb://localhost:27017/mydb" --gzip --archive=/backup/mydb.gz
# 恢复时删除现有数据
mongorestore --drop --uri="mongodb://localhost:27017/mydb" /backup/mydb/
# 恢复指定集合
mongorestore --uri="mongodb://localhost:27017/mydb" --collection=users /backup/mydb/users.bsonmongoexport / mongoimport
bash
# 导出为 JSON
mongoexport --uri="mongodb://localhost:27017/mydb" --collection=users --out=users.json
# 导出为 JSON(美化格式)
mongoexport --uri="mongodb://localhost:27017/mydb" --collection=users --pretty --out=users.json
# 导出为 CSV
mongoexport --uri="mongodb://localhost:27017/mydb" --collection=users --type=csv \
--fields=username,email,age --out=users.csv
# 查询条件导出
mongoexport --uri="mongodb://localhost:27017/mydb" --collection=users \
--query='{"status": "active"}' --out=active_users.json
# 导入 JSON
mongoimport --uri="mongodb://localhost:27017/mydb" --collection=users --file=users.json
# 导入 JSON(合并模式)
mongoimport --uri="mongodb://localhost:27017/mydb" --collection=users \
--file=users.json --mode=merge
# 导入 CSV
mongoimport --uri="mongodb://localhost:27017/mydb" --collection=users --type=csv \
--headerline --file=users.csv云备份(Atlas)
bash
# MongoDB Atlas 提供自动化云备份
# 功能:
# - 自动快照备份
# - 时间点恢复(PITR)
# - 跨区域备份
# - 按需快照
# 通过 Atlas 控制台或 API 管理
# Atlas CLI 示例:
atlas backups snapshots create --clusterName myCluster --desc "Manual backup"
atlas backups snapshots list --clusterName myCluster文件系统快照
bash
# 使用 LVM 快照
lvcreate -L 10G -s -n mongodb_snapshot /dev/vg0/mongodb
# 恢复
lvconvert --merge /dev/vg0/mongodb_snapshot
# 注意:快照前应先执行 fsyncLock,完成后解锁监控
内置命令
javascript
// 服务器状态
db.serverStatus()
// 数据库统计
db.stats()
// 集合统计
db.collection.stats()
// 实时监控
db.collection.watch()
// 当前操作
db.currentOp()
// 查看长时间运行的操作
db.currentOp({ "secs_running": { $gt: 5 } })
// 杀死操作
db.killOp(opId)
// 性能分析
db.setProfilingLevel(1, 50) // 记录超过 50ms 的操作
db.system.profile.find().sort({ ts: -1 }).limit(10)
// 查看复制状态
rs.printSlaveReplicationInfo()
rs.printReplicationInfo()关键监控指标
| 指标 | 说明 | 警告阈值 |
|---|---|---|
| connections.current | 当前连接数 | 接近 maxPoolSize |
| opcounters.* | 操作计数器 | 异常增长 |
| mem.resident | 内存使用量 | 接近物理内存 |
| page_faults | 页面错误 | 持续增长 |
| replication lag | 复制延迟 | > 10s |
| wiredTiger.cache.* | 缓存使用 | > 95% |
| network.bytesIn/Out | 网络流量 | 接近带宽上限 |
| db.collection.stats().size | 集合大小 | 持续增长 |
日志管理
yaml
# mongod.conf
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
logRotate: reopen
verbosity: 1
component:
query:
verbosity: 2
replication:
verbosity: 1
sharding:
verbosity: 1bash
# 慢查询日志
# 设置慢查询阈值(毫秒)
db.setProfilingLevel(1, 100)
# 查看慢查询
db.system.profile.find({ millis: { $gt: 100 } }).sort({ ts: -1 })
# 分析慢查询
db.system.profile.find({
millis: { $gt: 100 },
ns: "mydb.users"
}).sort({ millis: -1 }).limit(10)监控工具
bash
# mongostat - 实时统计
mongostat --uri="mongodb://localhost:27017" 5 # 每5秒输出一次
# mongotop - 读写时间统计
mongotop --uri="mongodb://localhost:27017" 10
# MongoDB Compass - 可视化监控
# MongoDB Atlas - 云监控
# Prometheus + Grafana - 自定义监控性能调优
索引优化
javascript
// 查看索引使用情况
db.collection.aggregate([
{ $indexStats: {} }
])
// 查看未使用的索引
db.collection.aggregate([
{ $indexStats: {} },
{ $match: { "accesses.ops": 0 } }
])
// 强制使用索引
db.collection.find().hint({ field: 1 })
// 禁用索引(测试用)
db.collection.find().hint({ $natural: 1 })
// 分析查询计划
db.collection.find().explain("executionStats")
// 检查索引大小
db.collection.totalIndexSize()查询优化
优化策略:
- 使用投影:只返回需要的字段
- 使用索引覆盖:查询字段都在索引中
- 避免
$where:使用$expr代替 - 限制结果集:使用
limit() - 批量操作:使用
insertMany、bulkWrite - 避免
$or与索引:改用$in
javascript
// 不好的查询
db.users.find({
$or: [
{ name: "Alice" },
{ name: "Bob" }
]
})
// 优化后
db.users.find({ name: { $in: ["Alice", "Bob"] } })
// 使用 $expr 替代 $where
// 不好的方式
db.users.find({ $where: "this.age > 18" })
// 优化后
db.users.find({ $expr: { $gt: ["$age", 18] } })内存优化
yaml
# WiredTiger 缓存配置
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 4 # 建议:物理内存的 50%-60%javascript
// 查看缓存使用情况
db.serverStatus().wiredTiger.cache
// 检查内存压力
db.serverStatus().mem连接池优化
javascript
// Node.js 连接池配置
const client = new MongoClient(uri, {
maxPoolSize: 100, // 最大连接数
minPoolSize: 10, // 最小连接数
maxIdleTimeMS: 30000, // 空闲连接超时
waitQueueTimeoutMS: 5000, // 获取连接超时
connectTimeoutMS: 10000,
socketTimeoutMS: 45000
})写入优化
javascript
// 批量写入
db.collection.insertMany([...], { ordered: false })
// 使用 bulkWrite
db.collection.bulkWrite([
{ insertOne: { document: {...} } },
{ updateOne: { filter: {...}, update: {...} } }
], { ordered: false })
// 调整写关注
db.collection.insertOne({...}, { writeConcern: { w: 1 } }) // 单节点确认安全配置
访问控制
javascript
// 创建管理员
use admin
db.createUser({
user: "admin",
pwd: "strongPassword123!",
roles: ["root"]
})
// 创建应用用户
use mydb
db.createUser({
user: "appUser",
pwd: "appPassword123!",
roles: [
{ role: "readWrite", db: "mydb" }
]
})
// 创建只读用户
db.createUser({
user: "readOnly",
pwd: "readOnly123!",
roles: [
{ role: "read", db: "mydb" }
]
})
// 更新用户密码
db.changeUserPassword("appUser", "newPassword123!")
// 删除用户
db.dropUser("oldUser")
// 查看用户权限
db.getUser("appUser")网络安全
yaml
# mongod.conf
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.1 # 限制绑定 IP
tls:
mode: requireTLS
certificateKeyFile: /path/to/cert.pem
CAFile: /path/to/ca.pem
allowConnectionsWithoutCertificates: false
security:
authorization: enabled
# 副本集认证
keyFile: /path/to/keyfilebash
# 生成 keyFile(副本集认证用)
openssl rand -base64 756 > /path/to/keyfile
chmod 400 /path/to/keyfile
# 防火墙配置(仅允许内网访问)
sudo ufw allow from 10.0.0.0/8 to any port 27017
sudo ufw enable防止 NoSQL 注入
javascript
// 错误示例 - 直接使用用户输入
const query = { username: req.body.username } // 危险!
// 正确示例 - 验证和转义
const username = req.body.username
if (typeof username !== 'string') {
throw new Error('Invalid username')
}
const query = { username: username }
// 使用 Mongoose 验证
const schema = new mongoose.Schema({
username: { type: String, required: true }
})
// 检查操作符注入
function sanitizeQuery(query) {
const forbiddenKeys = ['$where', '$function', '$accumulator']
function sanitize(obj) {
if (typeof obj !== 'object' || obj === null) return obj
for (const key of Object.keys(obj)) {
if (forbiddenKeys.includes(key)) {
delete obj[key]
} else if (typeof obj[key] === 'object') {
sanitize(obj[key])
}
}
return obj
}
return sanitize(JSON.parse(JSON.stringify(query)))
}审计
yaml
# mongod.conf
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/audit.log
filter: '{ atype: { $in: [ "authenticate", "createUser", "dropUser" ] } }'维护操作
压缩与修复
javascript
// 压缩集合(需要维护窗口)
db.runCommand({ compact: "users" })
// 修复数据库
db.repairDatabase() // 需要磁盘空间等于数据库大小
// 查看压缩效果
db.collection.stats()索引重建
javascript
// 后台重建索引
db.collection.createIndex({ field: 1 }, { background: true })
// 重建所有索引
db.collection.reIndex()数据迁移
javascript
// 迁移数据到新集合
db.source.aggregate([
{ $out: "destination" }
])
// 批量迁移
db.source.find().forEach(doc => {
db.destination.insertOne(doc)
})